home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / icon / contrib / dev.lha / dev / mcc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-17  |  9.5 KB  |  416 lines

  1. /*  Program: mcc
  2.  *  By:      Brent Callaghan
  3.  *  Date:    July 1984
  4.  *
  5.  *  Function: Runs the C compiler, passing all command line 
  6.  *        arguments. If the compiler returns a non-zero
  7.  *        result, the syntax errors are merged with the
  8.  *        source and the user's editor is invoked. The
  9.  *        cursor is placed on the first line in error.
  10.  *        Exit from the editor re-invokes the C compiler.
  11.  *        This loop continues until the C compiler exits
  12.  *        to the linker, the source file is not changed,
  13.  *        or the user kills mcc with a keyboard interrupt
  14.  *        after exiting the editor.
  15.  *
  16.  *        Environment variables EDITOR and COMPILER may
  17.  *        be used to set an alternative editor or compiler.
  18.  *
  19.  *              ~~~  PUBLIC DOMAIN  ~~~
  20.  *        
  21.  *       This program may be freely used and distributed
  22.  *       but I would rather you did not sell it.
  23.  *
  24.  ************************************************************
  25.  */
  26.  
  27.  /* bugs: 1. only edits the first source file with errors.        */
  28.  /*       2. copies the temporary back onto the original even if    */
  29.  /*          the original is newer                    */
  30.  
  31. #if 0
  32. Mcc (Merge C Compiler) behaves just like a C for an error free
  33. compile.  However, if the compiler finds syntax errors, it merges the
  34. error messages with the source and invokes your editor (default is vi)
  35. on the merged file.  On exiting the editor it strips the merged
  36. messages and if the source file was modified it re-runs the compiler
  37. for another try.
  38.  
  39. This posting contains a shell script and a C program with identical
  40. functionality.  The C program is noticeably faster.
  41.  
  42. Made in New Zealand -->  Brent Callaghan  @ Sun Microsystems
  43.              uucp: sun!bcallaghan
  44.              phone: (415) 691 6188
  45. #endif
  46.  
  47. #include <stdio.h>
  48. #include <ctype.h>
  49. #include <signal.h>
  50. #include <sys/types.h>
  51. #include <sys/stat.h>
  52.  
  53. #ifdef BSD
  54. #include <strings.h>
  55. #define strchr  index
  56. #define strrchr rindex
  57. #else
  58. #include <string.h>
  59. #endif
  60.  
  61. extern char * getenv();
  62. static char *errname  = "/tmp/errXXXXXX";
  63. static char mergename[128];
  64. static char *srcname;
  65. static char *editor, *edname, *compiler;
  66. static int pid, viedit, firsterr;
  67. static int chksum1, chksum2;
  68. static int    filevar, linevar, msgvar;
  69. extern char *re_comp();
  70. static char    errpat[1024], errpato[1024];
  71. static char    *errdfa;
  72. extern char    *braslist[], *braelist[];
  73.  
  74. /*
  75.  * Form 16 bit checksum of source line
  76.  */
  77. int 
  78. checksum(sum, line)
  79.     register int sum;
  80.     register char *line;
  81. {
  82.     while (*line++) {
  83.     if (sum & 1)
  84.         sum = (sum >> 1) + 0x8000;
  85.     else
  86.         sum >>= 1;
  87.  
  88.     sum = (sum + *line) & 0xFFFF;
  89.     }
  90.     return sum;
  91. }
  92.  
  93. int 
  94. runc(argv, errname)
  95.     char **argv;
  96.     char *errname;
  97. {
  98.     int status;
  99.  
  100.     switch (pid = fork()) {
  101.     case 0:            /* child */
  102.     (void) freopen(errname, "w", stderr);
  103.     execvp(compiler, argv);
  104.     perror("Couldn't exec compiler");
  105.     exit (1);
  106.  
  107.     case -1:            /* Error */
  108.     perror("Couldn't fork compiler");
  109.     exit (1);
  110.  
  111.     default:            /* Parent */
  112.     while (wait(&status) != pid);    /* wait for compile to finish */
  113.     break;
  114.     }
  115.     return ((status >> 8) & 0xFF);
  116. }
  117.  
  118. void 
  119. listerrs(errname)
  120.     char *errname;
  121. {
  122.     FILE *errfile;
  123.     char errline[BUFSIZ + 1];
  124.  
  125.     if ((errfile = fopen(errname, "r")) == NULL)
  126.     return;
  127.     while (fgets(errline, BUFSIZ, errfile) != NULL)
  128.     (void) fputs(errline, stderr);
  129.     (void) fclose(errfile);
  130.     (void) unlink(errname);
  131. }
  132.  
  133. void 
  134. edit(mergename)
  135.     char *mergename;
  136. {
  137.     int status;
  138.     char sfirsterr[6];
  139.  
  140.     switch (pid = fork()) {
  141.     case 0:            /* Child */
  142.     if (viedit) {
  143.         (void) sprintf(sfirsterr, "+%d", firsterr);
  144.         (void) printf(" vi %s %s\n", sfirsterr, mergename);
  145.         execlp(editor, "vi", sfirsterr, mergename, NULL);
  146.     } else {
  147.         (void) printf(" %s %s\n", edname, mergename);
  148.         execlp(editor, edname, mergename, NULL);
  149.     }
  150.     perror("Couldn't exec editor");
  151.     listerrs(errname);
  152.     exit (1);
  153.  
  154.     case -1:            /* Error */
  155.     perror("Couldn't fork editor");
  156.     listerrs(errname);
  157.     exit (1);
  158.  
  159.     default:            /* Parent */
  160.     while (wait(&status) != pid);    /* wait for editor to finish */
  161.     break;
  162.     }
  163. }
  164.  
  165. int 
  166. errinfo(errfile, srcname, errmsg)
  167.     FILE *errfile;
  168.     char *srcname, *errmsg;
  169. {
  170.     static char errline[BUFSIZ + 1];
  171.     char slineno[8];
  172.     char *p1;
  173.  
  174.     for (;;) {
  175.     /*    get next line from error message file    */
  176.     if (fgets(errline, BUFSIZ, errfile) == NULL)
  177.         return 0;
  178.  
  179.     errline[strlen(errline) - 1] = '\0';    /* trim newline */
  180.     p1 = errline;
  181.  
  182.     /*    does it match the pattern?    */
  183.     if (re_exec(p1, errdfa)) {
  184.         sprintf(srcname, "%.*s", braelist[filevar] - braslist[filevar],
  185.                         braslist[filevar]);
  186.         sprintf(slineno, "%.*s", braelist[linevar] - braslist[linevar],
  187.                         braslist[linevar]);
  188.         sprintf(errmsg, "%.*s", braelist[msgvar] - braslist[msgvar],
  189.                         braslist[msgvar]);
  190.         return atoi(slineno);
  191.         }
  192.     }
  193. }
  194.  
  195. char *merge(errname, mergename)
  196.     char *errname, *mergename;
  197. {
  198.     FILE *errfile, *srcfile, *mergefile;
  199.     int eof = 0, slineno, elineno, elines;
  200.     static char firstname[128];
  201.     char srcline[BUFSIZ + 1];
  202.     char srcname[128], errmsg[80];
  203.  
  204.     if ((errfile = fopen(errname, "r")) == NULL) {
  205.     perror(errname);
  206.     exit (1);
  207.     }
  208.     if ((firsterr = errinfo(errfile, srcname, errmsg)) == 0)
  209.     return NULL;
  210.  
  211.     if (access(srcname, 2) < 0)    /* writeable ? */
  212.     return NULL;
  213.  
  214.     if ((srcfile = fopen(srcname, "r")) == NULL) {
  215.     perror(srcname);
  216.     exit (1);
  217.     }
  218.     if (*mergename == '\0') {
  219.     char *p = strrchr(srcname, '/');
  220.     if (p == NULL)
  221.         p = srcname;
  222.     else
  223.         p++;
  224.     (void) sprintf(mergename, "/tmp/%d.%s", getpid(), p);
  225.     }
  226.     if ((mergefile = fopen(mergename, "w")) == NULL) {
  227.     perror(mergename);
  228.     exit (1);
  229.     }
  230.     slineno = 0;
  231.     elineno = firsterr;
  232.     elines = 0;
  233.     (void) strcpy(firstname, srcname);
  234.     chksum1 = 0;
  235.  
  236.     if (!viedit) {
  237.         (void) fprintf(mergefile, ">>>><<<< (%d)\n", firsterr + 1);
  238.         elines++;
  239.     }
  240.     while (!eof) {
  241.     if (!(eof = (fgets(srcline, BUFSIZ, srcfile) == NULL))) {
  242.         chksum1 = checksum(chksum1, srcline);
  243.         (void) fputs(srcline, mergefile);
  244.     }
  245.     slineno++;
  246.     while (slineno == elineno) {
  247.         elines++;
  248.         (void) fprintf(mergefile, ">>>> %s <<<<", errmsg);
  249.         if ((elineno = errinfo(errfile, srcname, errmsg)) == 0
  250.         || strcmp(firstname, srcname) != 0)
  251.         (void) fprintf(mergefile, " (last error)\n");
  252.         else
  253.         (void) fprintf(mergefile, " (%d)\n", elineno + elines);
  254.     }
  255.     }
  256.     (void) fclose(errfile);
  257.     (void) fclose(srcfile);
  258.     (void) fclose(mergefile);
  259.     return (firstname);
  260. }
  261.  
  262. /*
  263.  * Strip out merged error messages and compute checksum
  264.  */
  265. void 
  266. unmerge(mergename, srcname)
  267.     char *mergename, *srcname;
  268. {
  269.     FILE *mergefile, *srcfile;
  270.     char *p, srcline[BUFSIZ + 1];
  271.     struct stat merge, src;
  272.  
  273.     if (stat(mergename, &merge) != 0) {
  274.     perror(mergename);
  275.     exit(1);
  276.     }
  277.  
  278.     if (stat(srcname, &src) != 0) {
  279.     perror(srcname);
  280.     exit(1);
  281.     }
  282.  
  283.     if (merge.st_mtime < src.st_mtime) {    /* src is newer, don't */
  284.     return;                    /* crong it from tmp   */
  285.     }
  286.  
  287.     if ((mergefile = fopen(mergename, "r")) == NULL) {
  288.     perror(mergename);
  289.     exit (1);
  290.     }
  291.     if ((srcfile = fopen(srcname, "w")) == NULL) {
  292.     perror(srcname);
  293.     exit (1);
  294.     }
  295.     chksum2 = 0;
  296.     while (fgets(srcline, BUFSIZ, mergefile) != NULL) {
  297.     for (p = srcline; isspace(*p); p++);
  298.     if (strncmp(p, ">>>>", 4) != 0) {
  299.         chksum2 = checksum(chksum2, srcline);
  300.         (void) fputs(srcline, srcfile);
  301.     }
  302.     }
  303.  
  304.     (void) fclose(mergefile);
  305.     (void) fclose(srcfile);
  306. }
  307.  
  308. void 
  309. quit()
  310. {
  311.     (void) kill(pid, SIGTERM);
  312.     (void) unlink(errname);
  313.     (void) unlink(mergename);
  314.     exit (1);
  315. }
  316.  
  317. main(argc, argv)
  318.     int argc;
  319.     char *argv[];
  320. {
  321.     char    *p, *s, *d;
  322.     int i, status, nvars;
  323.  
  324.     if ((editor = getenv("EDITOR")) == NULL)
  325.     editor = "vi";
  326.     edname = (edname = strrchr(editor, '/')) == NULL ? editor : edname + 1;
  327.     viedit = strcmp(edname, "vi") == 0;
  328.  
  329.     if ((compiler = getenv("COMPILER")) == NULL)
  330.     compiler = "cc";
  331.     argv[0] = compiler;
  332.  
  333.     (void) mktemp(errname);
  334.  
  335.     signal(SIGINT, quit);
  336.     signal(SIGTERM, quit);
  337.     signal(SIGHUP, quit);
  338.  
  339.     if (p = getenv("ERRORPATTERN"))
  340.     strcpy(errpat, p);
  341.  
  342.     nvars = 0;
  343.  
  344.     /*  preprocess pattern to turn %f and %l into \(.*\) so that regex    */
  345.     /*  will remember the file and line numbers.                          */
  346.     for (s = errpat, d = errpato; *s;) {
  347.     if (*s == '%' && s[1] == 'f') {
  348.         *d++ = '\\'; *d++ = '('; *d++ = '.'; *d++ = '*';
  349.         *d++ = '\\'; *d++ = ')';
  350.         filevar = nvars++;
  351.         s += 2;
  352.         }
  353.     else if (*s == '%' && s[1] == 'm') {
  354.         *d++ = '\\'; *d++ = '('; *d++ = '.'; *d++ = '*';
  355.         *d++ = '\\'; *d++ = ')';
  356.         msgvar = nvars++;
  357.         s += 2;
  358.         }
  359.     else if (*s == '%' && s[1] == 'l') {
  360.         *d++ = '\\'; *d++ = '(';
  361.         *d++ = '['; *d++ = '0'; *d++ = '-'; *d++ = '9'; *d++ = ']';
  362.         *d++ = '*';
  363.         *d++ = '\\'; *d++ = ')';
  364.         s += 2;
  365.         linevar = nvars++;
  366.         }
  367.     else *d++ = *s++;
  368.     }
  369.  
  370.     errdfa = re_comp(errpato);
  371.  
  372.     while (status = runc(argv, errname)) {
  373.     if ((srcname = merge(errname, mergename)) == NULL) {
  374.         listerrs(errname);
  375.         exit (status);    /* couldn't merge */
  376.     }
  377.     edit(mergename);
  378.     (void) unlink(errname);
  379.  
  380.     signal(SIGINT,  SIG_IGN);
  381.     signal(SIGTERM, SIG_IGN);
  382.     signal(SIGHUP,  SIG_IGN);
  383.  
  384.     unmerge(mergename, srcname);
  385.     (void) unlink(mergename);
  386.  
  387.     signal(SIGINT,  quit);
  388.     signal(SIGTERM, quit);
  389.     signal(SIGHUP,  quit);
  390.  
  391.     if (chksum1 == chksum2)    /* file unchanged ? */
  392.         break;
  393.  
  394.     putchar(' ');
  395.     for (i = 0; i < argc; i++)
  396.         (void) printf("%s ", argv[i]);
  397.     putchar('\n');
  398.     }
  399.     listerrs(errname);
  400.     (void) unlink(errname);
  401.     exit (status);
  402. }
  403.  
  404. char *alloc(siz)
  405.     {
  406.     char *calloc();
  407.     char *r;
  408.     r = calloc(1, siz);
  409.     if (!r)
  410.         {
  411.         fprintf(stderr, "no memory\n");
  412.         exit(0);
  413.         }
  414.     return r;
  415.     }
  416.